home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Safari II 1.4 / Safari II.c < prev   
Text File  |  1991-10-19  |  46KB  |  2,001 lines

  1. /*
  2.     Code release for Safari II 1.1.3
  3.     Changes since 1.0 release:
  4.         It's now FREE! (please send comments & a postcard)
  5.         The sicn's were eliminated from the apple menu so it should now work on older systems
  6.         The dialog box in which I begged for a job is gone (I've found work, thanks!)
  7.         The option to 'score when hit' in rectangle surrounding animal now works.
  8.            
  9.     There still seems to be problems with the sound playing on older 68000 Macs.  Any advice on
  10.     this problem, or more descript diagnoses would be appreciated.
  11.  
  12.     SAFARI II © 1991 by John Gallaugher
  13.         A program written in Think C.  Portions copyright Symantec and Apple Computer.
  14.  
  15.     In 1985 I wrote a program called Safari to try to teach myself the Macintosh toolbox.  
  16.     The original Safari was simple and cute, but it was also a program which doesn't work on
  17.     today's machines.  Safari II is an update to the orginal Safari.  It should work on all
  18.     Macs with at least 1 meg of memory running system 6.0.x or greater.
  19.     
  20.     Although I have done quite a bit of Macintosh database development, I have never programmed
  21.     professioanlly in the toolbox or in C.  As such, please excuse the clumsiness of some of
  22.     this code.  I am distributing the source code and game for free in hopes that it will help
  23.     others learn some of the basics of Macintosh game development.  My experience has found that
  24.     there's not much free source code out there to help the would-be game developmer.  I hope my
  25.     modest submission helps some folks get started.
  26.     
  27.     Although this product is offerd for free, I DO ask those pros and semi-pros out there to
  28.     offer suggestions on how I can improve this code.  Since I'm pretty green in toolbox coding
  29.     I would greatly appreciate advice.  Please don't hold back,  criticize me to the hilt!  
  30.     I need and welcome the help.
  31.     
  32.     Also, please don't distribute any modified versions of Safari.  I welcome you to learn from
  33.     the code and encourage you to produce original work, but I would like all updates of the game
  34.     to pass through me.
  35.     
  36.     Lastly, please send comments!  I love to hear from folks who have received my game.  
  37.     My E-Mail addresses are:
  38.     CIS - 70137,763
  39.     AOL - GALLAUGHER
  40.     
  41.     If you'd care to send any U.S. Mail (I love postcards), forward
  42.     them to:
  43.         Safari
  44.         c/o John Gallaugher
  45.         Three Allegheny Center #118
  46.         Pittsburgh, PA 15212
  47.         
  48.     A special thanks to the helpful folks at the Boston Computer Society's MacTech group, and to
  49.     the outstanding faculty of the Boston College Computer Science Program for their patient help
  50.     in answering my silly questions.
  51.     
  52.     This program seems to work fine on my 4 meg LC running under System 7.0 if you run into any
  53.     problems, PLEASE let me know.
  54.     
  55.     RESOURCE NOTE:  All sounds were created using the microphone on a Macintosh LC.
  56.         All pictures were created using MacPaint.  The 'RGN ' resources which are used to detect
  57.         the boundries of the animal bodies were created using a utilty program called 'Regions'
  58.         created by the late Duane Blehm (it should be available via local user groups and on-line
  59.         services).  All other resources were created directly in ResEdit.
  60. */
  61.  
  62. #include <Sound.h> /* adds routines need to play Asynch Sound */
  63.  
  64. /*
  65.     sorry about any inconsistencies in declaring resource numbers.  I started
  66.     and stopped the project several times and added things on the fly without
  67.     thinking of a logical numbering system.  Feel free to suggest a convention.
  68. */
  69.  
  70. #define M_T_F                    ((void *) -1L) /* used in setting up windows */
  71. #define    BASE_RES_ID                400
  72. #define    REMOVE_ALL_EVENTS        0
  73.  
  74. #define    BORDER                    6  /* number of pixels between window and screen width */
  75. #define    TITLE_BAR_HEIGHT        19 /* I guessed, is there a TB call to get this? */
  76. #define    TICK_DELAY                1  /* this cycles the animation through 1 tick, or 1/60th of a second */
  77.  
  78. /* Menu IDs */
  79. #define    APPLE_MENU_ID            1
  80. #define    FILE_MENU_ID            401
  81. #define    EDIT_MENU_ID            402
  82. #define    GAME_MENU_ID            403
  83.  
  84. /* Menu Items */
  85. #define    ABOUT_ITEM                1
  86. #define    NEW_GAME_ITEM            1
  87. #define    PAUSE_RESUME_ITEM        2
  88. #define    STOP_ITEM                3
  89. #define    QUIT_ITEM                5
  90. #define    UNDO_ITEM                1
  91. #define    CUT_ITEM                3
  92. #define    COPY_ITEM                4
  93. #define    PASTE_ITEM                5
  94. #define    CLEAR_ITEM                6
  95. #define    GAME_OPTIONS_ITEM        1
  96. #define    ANIMAL_POINT_VALUES_ITEM    2
  97. #define    HALL_OF_FAME_ITEM        3
  98.  
  99. /* Alerts */
  100. #define    ERROR_ALERT_ID            401
  101. #define    ERROR_EDIT_TEXT            402
  102.  
  103. /* Dialogs */
  104. #define    GAME_OPTIONS_DIALOG        200
  105. #define    SAVE_HIGH_SCORES_DIALOG    300
  106. #define    ANIMAL_POINT_VALUES_DIALOG    129
  107. #define    INTRO_DIALOG            475
  108. #define    ABOUT_DIALOG            476
  109. #define    PLAYER_NAME_DIALOG        500
  110. #define    HALL_OF_FAME_DIALOG        550
  111.  
  112. /* Dialog Items */
  113. #define OK_BUTTON                1
  114. #define    SAVE_AND_CLEAR_BUTTON    2
  115. #define    CANCEL_BUTTON            3
  116. #define    TIMED_RADIO                4
  117. #define    ESCAPED_RADIO            5
  118. #define    NINE_INCH_RADIO            6
  119. #define    CURRENT_SCREEN_RADIO    7
  120. #define    INCREASE_YES_RADIO        8
  121. #define    INCREASE_NO_RADIO        9
  122. #define    IN_BOX_SURROUNDING_ANIMAL_RADIO    10
  123. #define    IN_ANIMAL_OUTLINE_RADIO    11
  124. #define    MINUTES                    12
  125. #define    SECONDS                    13
  126. #define    MAX_ESCAPED                14
  127. #define SPEED_POP_UP            15
  128. #define    SLOW_RADIO                25
  129. #define    MEDIUM_RADIO            26
  130. #define    FAST_RADIO                27
  131. #define    PLAYER_NAME_ITEXT        3
  132. #define    CLEAR_SCORES_BUTTON        2
  133. #define    OK_APV_DBOX                9
  134. #define    SHOW_INTRO_SCREEN        2
  135. #define    HELP_BUTTON                3
  136. #define    HEAD_ICON                5
  137. #define    OUCH_ICON                7
  138.  
  139. /* icons */
  140. #define    MY_HEAD                    476
  141. #define    OUCH_HEAD                477
  142.  
  143. /* Error Strings */
  144. #define    NO_MBAR                    BASE_RES_ID
  145. #define    NO_MENU                    BASE_RES_ID + 1
  146. #define    NO_WIND                    BASE_RES_ID + 3
  147. #define NO_STR                    BASE_RES_ID + 4
  148. #define CANT_LOAD_SND            BASE_RES_ID + 5
  149. #define    MINUTES_ERROR            BASE_RES_ID + 6
  150. #define    SECONDS_ERROR            BASE_RES_ID + 7
  151. #define    ESCAPED_ERROR            BASE_RES_ID + 8
  152. #define    NO_RGN                    BASE_RES_ID + 9
  153.  
  154. /* 'STR ' resource IDs */
  155. #define    TIMED_OR_ESCAPED        200
  156. #define ANIMAL_SPEED            201
  157. #define    WINDOW_SIZE                202
  158. #define    INCREASE_SPEED            203
  159. #define    SCORE_WHEN_HIT            204
  160. #define    MINUTES_STRING            212
  161. #define    SECONDS_STRING            213
  162. #define    MAX_ESCAPED_STRING        214
  163. #define    HIGH_SCORE_STRING        128
  164. #define    HIGH_NAMES_STRING        131
  165.  
  166. /* cursor */
  167. #define    CROSSHAIR                BASE_RES_ID
  168.  
  169. /* button types */
  170. #define    PLAY_AGAIN_BUTTON        128
  171. #define    QUIT_BUTTON                129
  172.  
  173. /* sounds */
  174. #define    TARZAN_SOUND            409
  175. #define    INTRO_SOUND                410
  176. #define    OUCH_SOUND                411
  177.  
  178. /* PICTs */
  179. #define ANIMAL_PICTURE            BASE_RES_ID  /* picture containing animal bitmaps */
  180.  
  181. /* animals */
  182. #define    RHINO                    0
  183. #define    ELEPHANT                1
  184. #define    ZEBRA                    2
  185. #define    GORILLA                    3
  186. #define    ANTELOPE                4
  187. #define    GIRAFFE                    5
  188. #define    LION                    6
  189. #define    CHEETAH                    7
  190. #define WARTHOG                    8
  191.  
  192. #define    DRAG_THRESHOLD            30
  193.  
  194. #define    WINDOW_HOME_LEFT        5
  195. #define    WINDOW_HOME_TOP            45
  196. #define    NEW_WINDOW_OFFSET        20
  197.  
  198. #define    HOPELESSLY_FATAL_ERROR    "\pGoodness knows what happened!"
  199.  
  200. /* this structure is used for each row.  There is one animal per row. */
  201. struct
  202. {
  203.     Rect    rect;        /* the rect into which the animal bitmap is drawn */
  204.     Boolean    running;    /* is an animal running in the row? */
  205.     int        animal;        /* what type of animal is it? */
  206.     int        speed;        /* how fast does it go? */
  207.     int        step;        /* alternates each pass so that different animal positions are
  208.                             drawn, creating the illusion of a stride */
  209. }
  210. row[20];                /* there can be no more than 20 rows of animals */
  211.  
  212. struct
  213. {
  214.     Rect    rect[2];    /* source rectangles from which animal bitmaps are taken */
  215.     int        value;        /* point value of the animal */
  216.     int        speed;
  217.     int        region[2];    /* array containing two regions for each animal; */
  218.                         /* used to check if someone has clicked inside animal outline */
  219. }
  220. animal[9];                /* there are nine different animals */
  221.  
  222. /* unusual variable names in comments */
  223.  
  224. /*
  225.     increaseSpeed is true when Game Options dialog has the speed of the game
  226.         increase as the score increases.
  227.     easyShoot allows player to score by clicking in a rect surrounding the animal
  228.         instead of clicking directly within outline of the animal (good for kids).
  229.     loopValue keeps track of a group of statements which mimic a for loop, but which
  230.         increment only once every pass through the animation procedure.  This is done
  231.         instead of a for loop so the game can respond to an event after each animal
  232.         is drawn.  
  233.     speedFactor and speedIncrease regulate initial speed of game and increase
  234.         in speed as game play continues
  235. */
  236.  
  237. Boolean            gDone, gamePaused, gameOver, increaseSpeed, easyShoot;
  238. Boolean            standardWindow, showHighScores, escapedGame;
  239. MenuHandle        gAppleMenu, gFileMenu, gEditMenu;
  240. Rect            gDragRect, whereAnimalsRun; /* latter is where animation occurs */
  241. int                windowHeight, windowWidth, lastTicks;
  242.  
  243. int                gameScore, animalsEscaped, animalRows;
  244. int                loopValue, speedFactor, speedIncrease;
  245. long            maxEscaped, timeRemaining, lastTime, topScores[3];
  246.  
  247. WindowPtr        gameWindow;
  248. GrafPtr            offscreen;
  249. ControlHandle    playAgainControl, quitControl;
  250. Str255            preferenceString[8], name;
  251.  
  252. pascal Boolean GameOptionsDProc(DialogPtr theDialog, EventRecord *theEvent, int *itemHit);
  253.  
  254. main(void)
  255. {
  256.     ToolBoxInit();
  257.     
  258.     SetUpFirstGlobals();
  259.     
  260.     MenuBarInit();
  261.     WindowInit();
  262.     SetUpDragRect();
  263.     
  264.     InitOffscreen();
  265.     SetUpGame();
  266.     IntroDialog();
  267.  
  268.     EventLoop();
  269. }
  270.  
  271. ToolBoxInit(void)
  272. {
  273.     InitGraf(&thePort);
  274.     InitFonts();
  275.     InitWindows();
  276.     InitMenus();
  277.     TEInit();
  278.     InitDialogs(NULL);
  279.     InitCursor();
  280.     MaxApplZone();
  281.     MoreMasters();
  282.     MoreMasters();
  283.     MoreMasters();
  284.     MoreMasters();
  285.     FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
  286. }
  287.  
  288. SetUpFirstGlobals(void)
  289. {    
  290.     DialogPtr    theDialog;
  291.  
  292.     showHighScores = TRUE;
  293. /*
  294.     DialogInit() requires that the Dialog be created since it calls the DITL,
  295.     so we create the dialog, call the procedure, and dispose of the dialog
  296.     without ever displaying the dialog
  297. */
  298.     if ((theDialog = GetNewDialog(GAME_OPTIONS_DIALOG, NULL, M_T_F)) == NULL)
  299.     {
  300.         ErrorHandler(NO_WIND);
  301.     }
  302.     lastTicks = TickCount();
  303.     DialogInit(theDialog);
  304.     DisposDialog(theDialog);
  305. }
  306.  
  307. MenuBarInit(void)
  308. {
  309.     Handle    myMenuBar;
  310.     
  311.     if ((myMenuBar = GetNewMBar(BASE_RES_ID)) == NULL) 
  312.     {
  313.         ErrorHandler(NO_MBAR);
  314.     }
  315.     SetMenuBar(myMenuBar);
  316.     
  317.     if ((gAppleMenu = GetMHandle(APPLE_MENU_ID)) == NULL)
  318.     {
  319.         ErrorHandler(NO_MENU);
  320.     }
  321.     AddResMenu(gAppleMenu, 'DRVR');
  322.     
  323.     if ((gEditMenu = GetMHandle(EDIT_MENU_ID)) == NULL)
  324.     {
  325.         ErrorHandler(NO_MENU);
  326.     }
  327.     
  328.     if ((gFileMenu = GetMHandle(FILE_MENU_ID)) == NULL)
  329.     {
  330.         ErrorHandler(NO_MENU);
  331.     }
  332.     
  333.     DrawMenuBar();
  334. }
  335.  
  336. WindowInit(void)
  337. {
  338.     if ((gameWindow = GetNewWindow(BASE_RES_ID, NULL, M_T_F)) == NULL)
  339.     {
  340.         ErrorHandler(NO_WIND);
  341.     }
  342.     playAgainControl = GetNewControl(PLAY_AGAIN_BUTTON, gameWindow);
  343.     quitControl = GetNewControl(QUIT_BUTTON, gameWindow);
  344. }
  345.  
  346. CenterWindow(WindowPtr theWindow)
  347. {
  348.     int        newLeft, newTop;
  349.     Rect    windowRect = theWindow->portRect;
  350.     Rect    screenRect = screenBits.bounds;
  351.     
  352.     newLeft = ((screenRect.right - screenRect.left) - (windowRect.right - windowRect.left)) / 2;
  353.     newTop = ((screenRect.bottom - (screenRect.top + MBarHeight + TITLE_BAR_HEIGHT)) 
  354.         - (windowRect.bottom - windowRect.top)) / 2;
  355.     MoveWindow(theWindow, newLeft, newTop + MBarHeight + TITLE_BAR_HEIGHT, TRUE);
  356.     ShowWindow(theWindow);
  357. }
  358.  
  359. AdjustWindowSize(void)
  360. {
  361.     Rect    windowRect = gameWindow->portRect;
  362.     int        h, v;
  363.     
  364.     SetPort(gameWindow);
  365.     
  366.     if (!standardWindow) /* if it's not the 9" screen window, then */
  367.     {
  368.         SizeWindow(gameWindow,
  369.             screenBits.bounds.right - BORDER, 
  370.             screenBits.bounds.bottom - (MBarHeight + BORDER + TITLE_BAR_HEIGHT),
  371.             TRUE);
  372.     }
  373.     else
  374.     {
  375.         SizeWindow(gameWindow, 506, 298, TRUE);
  376.     }
  377.     
  378.     windowRect = gameWindow->portRect;
  379.     
  380.     windowWidth = windowRect.right - windowRect.left;
  381.     windowHeight = windowRect.bottom - windowRect.top;
  382.     
  383.     CenterWindow(gameWindow);
  384.     TextFont(systemFont);
  385.     
  386.     v = windowHeight / 2 + 20;
  387.     h = windowWidth / 2 - 100;
  388.     MoveControl(playAgainControl, h, v);
  389.     h = windowWidth / 2 + 20;
  390.     MoveControl(quitControl, h, v);
  391. }
  392.  
  393. Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
  394. {
  395.     GrafPtr savePort;
  396.     GrafPtr newPort;
  397.  
  398.     GetPort(&savePort);    /* need this to restore thePort after OpenPort */
  399.  
  400.     newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */
  401.     if (MemError() != noErr)
  402.     {
  403.         return false;                 /* failed to allocate the off-screen port */
  404.     }
  405. /*
  406.     the call to OpenPort does the following . . . 
  407.         allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  408.         sets portBits to screenBits
  409.         sets portRect to screenBits.bounds
  410.         etc. (see IM I-163,164)
  411.         side effect: does a SetPort(&offScreen)
  412. */
  413.     OpenPort(newPort);
  414.     /* make bitmap the size of the bounds that caller supplied */
  415.     newPort->portRect = *inBounds;
  416.     newPort->portBits.bounds = *inBounds;
  417.     RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */
  418.     RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */
  419.  
  420.     /* rowBytes is size of row, it must be rounded up to an even number of bytes */
  421.     newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;
  422.  
  423.     /* number of bytes in BitMap is rowBytes * number of rows */
  424.     /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr */
  425.     newPort->portBits.baseAddr =
  426.         NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds->top));
  427.     if (MemError() != noErr)
  428.     {   /* check to see if we had enough room for the bits */
  429.         SetPort(savePort);
  430.         ClosePort(newPort);      /* dump the visRgn and clipRgn */
  431.         DisposPtr((Ptr)newPort); /* dump the GrafPort */
  432.         return false;            /* tell caller we failed */
  433.     }
  434.     /* since the bits are just memory, let's clear them before we start */
  435.     EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */
  436.     *newOffscreen = newPort;
  437.     SetPort(savePort);
  438.     return true;               /* tell caller we succeeded! */
  439. }
  440.  
  441. void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
  442. {
  443.     ClosePort(oldOffscreen);                        /* dump the visRgn and clipRgn */
  444.     DisposPtr(oldOffscreen->portBits.baseAddr);        /* dump the bits */
  445.     DisposPtr((Ptr)oldOffscreen);                    /* dump the port */
  446. }
  447.  
  448. InitOffscreen(void)
  449. {
  450.     Rect    offScreenRect;
  451.     
  452.     SetRect(&offScreenRect, 0, 0, 227, 151);         /* size of ANIMAL_PICTURE rect */
  453.  
  454.     if (!CreateOffscreenBitMap(&offscreen, &offScreenRect)) 
  455.     {
  456.         SysBeep(1);
  457.         ExitToShell();
  458.     }
  459.     
  460.     SetPort(offscreen);
  461.     DrawPicture(GetPicture(ANIMAL_PICTURE), &offScreenRect);
  462.     SetPort(gameWindow);
  463. }
  464.  
  465. SetUpDragRect(void)
  466. {
  467.     gDragRect = screenBits.bounds;
  468.     gDragRect.left += DRAG_THRESHOLD;
  469.     gDragRect.right -= DRAG_THRESHOLD;
  470.     gDragRect.bottom -= DRAG_THRESHOLD;
  471. }
  472.  
  473. DoSound(int whichOne, Boolean asynch)
  474. {
  475.     Handle                    theSnd;
  476.     static SndChannelPtr    chanPtr;
  477.     OSErr                    err;
  478.  
  479.     theSnd = GetResource('snd ', whichOne);
  480.     MoveHHi((Handle) theSnd);
  481.     HLock((Handle) theSnd);
  482.     if (theSnd != NULL) 
  483.     {
  484.         if (chanPtr != NULL)
  485.         {
  486.             (void) SndDisposeChannel(chanPtr, TRUE);
  487.             chanPtr = NULL;
  488.         }
  489.         
  490.         chanPtr = NULL;
  491.         
  492.         err = SndNewChannel(&chanPtr, 0, 0, NULL);
  493.         
  494.         if ((asynch) && (err == noErr))
  495.         {
  496.             (void) SndPlay(chanPtr, theSnd, TRUE);
  497.         }
  498.         else
  499.         {
  500.             (void) SndPlay(NULL, theSnd, FALSE);
  501.         }
  502.     }
  503.     HUnlock((Handle) theSnd);
  504. }
  505.  
  506. SetUpGame(void)
  507. {
  508.     register int    i;
  509.     long            stringValue;
  510.     Rect            windowRect;
  511.     
  512.     SetPreferences();                                 /* get current game settings */
  513.     if (showHighScores)
  514.     {
  515.         GetHighScores();
  516.     }
  517.     AdjustWindowSize();
  518.     HideControl(playAgainControl);
  519.     HideControl(quitControl);
  520.  
  521.     SetRect(&windowRect, 0, 0, windowWidth, windowHeight);
  522.     EraseRect(&windowRect);
  523.     speedIncrease = 0;
  524.     
  525.     /* Set Animal Values */
  526.     
  527.     SetRect(&animal[RHINO].rect[0], 2, 2, 35, 35);
  528.     SetRect(&animal[RHINO].rect[1], 40, 2, 73, 35);
  529.     animal[RHINO].value = 10;
  530.     animal[RHINO].speed = 2;
  531.     animal[RHINO].region[0] = 400;
  532.     animal[RHINO].region[1] = 401;
  533.                 
  534.     SetRect(&animal[ELEPHANT].rect[0], 2, 40, 35, 73);
  535.     SetRect(&animal[ELEPHANT].rect[1], 40, 40, 73, 73);
  536.     animal[ELEPHANT].value = 10;
  537.     animal[ELEPHANT].speed = 2;
  538.     animal[ELEPHANT].region[0] = 402;
  539.     animal[ELEPHANT].region[1] = 403;
  540.                 
  541.     SetRect(&animal[ZEBRA].rect[0], 2, 78, 35, 111);
  542.     SetRect(&animal[ZEBRA].rect[1], 40, 78, 73, 111);
  543.     animal[ZEBRA].value = 60;
  544.     animal[ZEBRA].speed = 4;
  545.     animal[ZEBRA].region[0] = 404;
  546.     animal[ZEBRA].region[1] = 405;
  547.         
  548.     SetRect(&animal[GORILLA].rect[0], 2, 116, 35, 149);
  549.     SetRect(&animal[GORILLA].rect[1], 40, 116, 73, 149);
  550.     animal[GORILLA].value = 50;
  551.     animal[GORILLA].speed = 3;
  552.     animal[GORILLA].region[0] = 406;
  553.     animal[GORILLA].region[1] = 407;
  554.             
  555.     SetRect(&animal[ANTELOPE].rect[0], 78, 2, 111, 35);
  556.     SetRect(&animal[ANTELOPE].rect[1], 116, 2, 149, 35);
  557.     animal[ANTELOPE].value = 75;
  558.     animal[ANTELOPE].speed = 5;
  559.     animal[ANTELOPE].region[0] = 408;
  560.     animal[ANTELOPE].region[1] = 409;
  561.         
  562.     SetRect(&animal[GIRAFFE].rect[0], 78, 40, 111, 73);
  563.     SetRect(&animal[GIRAFFE].rect[1], 116, 40, 149, 73);
  564.     animal[GIRAFFE].value = 60;
  565.     animal[GIRAFFE].speed = 4;
  566.     animal[GIRAFFE].region[0] = 410;
  567.     animal[GIRAFFE].region[1] = 411;
  568.                 
  569.     SetRect(&animal[LION].rect[0], 78, 78, 111, 111);
  570.     SetRect(&animal[LION].rect[1], 116, 78, 149, 111);
  571.     animal[LION].value = 75;
  572.     animal[LION].speed = 5;
  573.     animal[LION].region[0] = 412;
  574.     animal[LION].region[1] = 413;
  575.             
  576.     SetRect(&animal[CHEETAH].rect[0], 78, 116, 111, 149);
  577.     SetRect(&animal[CHEETAH].rect[1], 116, 116, 149, 149);
  578.     animal[CHEETAH].value = 80;
  579.     animal[CHEETAH].speed = 6;
  580.     animal[CHEETAH].region[0] = 414;
  581.     animal[CHEETAH].region[1] = 415;
  582.                 
  583.     SetRect(&animal[WARTHOG].rect[0], 154, 2, 187, 35);
  584.     SetRect(&animal[WARTHOG].rect[1], 192, 2, 225, 35);
  585.     animal[WARTHOG].value = 60;
  586.     animal[WARTHOG].speed = 4;
  587.     animal[WARTHOG].region[0] = 416;
  588.     animal[WARTHOG].region[1] = 417;
  589.             
  590.     gameScore = 0;
  591.     
  592.     if (escapedGame)
  593.     {
  594.         animalsEscaped = 0;
  595.     }
  596.     else
  597.     {
  598.         StringToNum(preferenceString[MINUTES], &stringValue);
  599.         timeRemaining = stringValue * 60;
  600.         StringToNum(preferenceString[SECONDS], &stringValue);
  601.         timeRemaining += stringValue;
  602.         GetDateTime(&lastTime);
  603.     }
  604.     
  605.     DrawScoreBar();
  606.     
  607.     SetRect(&whereAnimalsRun, 0, 20, windowWidth, windowHeight);
  608.         
  609.     animalRows = (windowHeight - 20) / 33;
  610.     
  611.     if (animalRows > 20)
  612.     {
  613.         animalRows = 20;
  614.     }
  615.             
  616.     for (i = 0; i < animalRows; i++)
  617.     {
  618.         SetRect(&row[i].rect, 0, 33 * i + 20, 33, 33 * i + 53);
  619.         row[i].running = FALSE;
  620.     }
  621.     loopValue = 0;
  622.     gamePaused = FALSE;
  623.     gameOver = FALSE;
  624.     
  625. }
  626.  
  627. SetPreferences(void)
  628. {
  629.     register int    i;
  630.     long            currentSetting;
  631.     
  632.     for (i = 0; i <= 4; i++)
  633.     {
  634.         StringToNum(preferenceString[i], ¤tSetting);
  635.         switch (currentSetting)
  636.         {
  637.             case TIMED_RADIO:
  638.             case ESCAPED_RADIO:
  639.                 escapedGame = (currentSetting == ESCAPED_RADIO);
  640.                 break;
  641.             case NINE_INCH_RADIO:
  642.             case CURRENT_SCREEN_RADIO:
  643.                 standardWindow = (currentSetting == NINE_INCH_RADIO);
  644.                 break;
  645.             case INCREASE_YES_RADIO:
  646.             case INCREASE_NO_RADIO:
  647.                 increaseSpeed = (currentSetting == INCREASE_YES_RADIO);
  648.                 break;
  649.             case SLOW_RADIO:
  650.                 speedFactor = 1;
  651.                 break;
  652.             case MEDIUM_RADIO:
  653.                 speedFactor = 3;
  654.                 break;
  655.             case FAST_RADIO:
  656.                 speedFactor = 5;
  657.                 break;
  658.             case IN_ANIMAL_OUTLINE_RADIO:
  659.             case IN_BOX_SURROUNDING_ANIMAL_RADIO:
  660.                 easyShoot = (currentSetting == IN_BOX_SURROUNDING_ANIMAL_RADIO);
  661.                 break;
  662.             default:
  663.                 break;
  664.         }
  665.     }
  666.     StringToNum(preferenceString[MAX_ESCAPED], &maxEscaped);
  667. }
  668.  
  669. GetHighScores(void)
  670. {
  671.     register int    i;
  672.     StringHandle    theString;
  673.                 
  674.     for (i = 0; i <= 2; i++)
  675.     {
  676.         if ((theString = GetString(HIGH_SCORE_STRING + i)) == NULL)
  677.             ErrorHandler(NO_STR);
  678.         MoveHHi((Handle) theString);
  679.         HLock((Handle) theString);    
  680.         StringToNum(*theString, &topScores[i]);
  681.         HUnlock((Handle) theString);
  682.     }
  683. }
  684.  
  685. DrawScoreBar(void)
  686. {
  687.     Str255    scoreString;
  688.     int        length;
  689.     Rect    theRect;
  690.     
  691.     SetRect(&theRect, 0, 0, windowWidth, 20);
  692.     EraseRect(&theRect);
  693.     
  694.     MoveTo(2, 17);
  695.     DrawString("\pScore: ");
  696.     NumToString(gameScore, scoreString);
  697.     DrawString(scoreString);
  698.  
  699.     if (showHighScores)
  700.     {
  701.         PostHighScore();
  702.     }
  703.     
  704.     if (escapedGame)
  705.     {
  706.         length = StringWidth("\pAnimals Escaped: 500") + 2;
  707.         MoveTo(windowWidth - length, 17);
  708.         NumToString(animalsEscaped, scoreString);
  709.         DrawString("\pAnimals Escaped: ");
  710.         DrawString(scoreString);
  711.     }
  712.     else
  713.     {
  714.         length = StringWidth("\pTime Remaining: 00:00") + 2;
  715.         MoveTo(windowWidth - length, 17);
  716.         DrawString("\pTime Remaining: ");
  717.         PostTimeRemaining();
  718.     }
  719. }
  720.  
  721. PostTimeRemaining(void)
  722. {
  723.     long    diffTime, currentTime;
  724.     int        mins, secs, length;
  725.     Str255    timeString;
  726.     Rect    timeRect;
  727.     
  728.     GetDateTime(¤tTime);
  729.     diffTime = currentTime - lastTime;
  730.     if (diffTime > 0)
  731.     {
  732.         length = StringWidth("\p00:00") + 2;
  733.         SetRect(&timeRect, windowWidth - length, 0, windowWidth, 17);
  734.         EraseRect(&timeRect);
  735.         MoveTo(windowWidth - length, 17);
  736.         timeRemaining -= diffTime;
  737.         if (timeRemaining > 0)
  738.         {
  739.             mins = timeRemaining / 60;
  740.             NumToString(mins, timeString);
  741.             DrawString(timeString);
  742.             DrawString("\p:");
  743.             secs = timeRemaining - mins * 60;
  744.             if (secs < 10)
  745.             {
  746.                 DrawString("\p0");
  747.             }
  748.             NumToString(secs, timeString);
  749.             DrawString(timeString);
  750.         }
  751.         else
  752.         {
  753.             DrawString("\p0:00");
  754.             EndGame();
  755.         }
  756.     }
  757.     GetDateTime(&lastTime);
  758. }
  759.  
  760. PostHighScore(void)
  761. {
  762.     StringHandle    theString;
  763.     int                length;
  764.     
  765.     if ((theString = GetString(HIGH_SCORE_STRING)) == NULL)
  766.     {
  767.         ErrorHandler(NO_STR);
  768.     }
  769.     MoveHHi((Handle) theString);
  770.     HLock((Handle) theString);
  771.     
  772.     length = StringWidth("\pHigh Score: ") + 2 + StringWidth(*theString);
  773.     MoveTo((windowWidth - length) / 2, 17);
  774.     DrawString("\pHigh Score: ");
  775.     DrawString(*theString);
  776.     
  777.     HUnlock((Handle) theString);
  778. }
  779.  
  780. EventLoop(void)
  781. {
  782.     Boolean        hasGNE = WNEAvailable();
  783.     RgnHandle    cursorRgn = NewRgn();
  784.     Boolean        gotEvent;
  785.     EventRecord    event;
  786.     
  787.     gDone = FALSE;
  788.     
  789.     while (!gDone)
  790.     {
  791.         if (hasGNE)
  792.         {
  793.             gotEvent = WaitNextEvent(everyEvent, &event, (long)NULL, cursorRgn);
  794.         }
  795.         else
  796.         {
  797.             SystemTask();
  798.             gotEvent = GetNextEvent(everyEvent, &event);
  799.         }
  800.         
  801.         AdjustCursor(event.where);
  802.         
  803.         if (gotEvent)
  804.         {
  805.             DoEvent(event);
  806.         }
  807.         else
  808.         {
  809.             DoIdle();
  810.         }
  811.     }
  812. }
  813.  
  814. AdjustCursor(Point where)
  815. {    
  816.     if (FrontWindow() != gameWindow)
  817.     {
  818.         SetCursor(&arrow);
  819.     }
  820.     else
  821.     {
  822.         GlobalToLocal(&where);
  823.         if (PtInRect(where, &whereAnimalsRun))
  824.         {
  825.             SetCursor(*GetCursor(CROSSHAIR));
  826.         }
  827.         else
  828.         {
  829.             SetCursor(&arrow);
  830.         }
  831.     }
  832. }
  833.  
  834. DoEvent(EventRecord event)
  835. {
  836.     GrafPtr        oldPort;
  837.  
  838.     switch (event.what)
  839.     {
  840.         case mouseDown:
  841.             DoMouseDown(event);
  842.             break;
  843.         case keyDown:
  844.         case autoKey:
  845.             if ((event.modifiers & cmdKey) != 0)
  846.             {
  847.                 AdjustMenus();
  848.                 DoMenuChoice(MenuKey(event.message & charCodeMask));
  849.             }
  850.             break;
  851.         case updateEvt:
  852.             if (!IsDAWindow((WindowPtr) event.message))
  853.             {
  854.                 GetPort(&oldPort);
  855.                 SetPort((GrafPtr) event.message);
  856.                 BeginUpdate((GrafPtr) event.message);
  857.                 GetDateTime(&lastTime);
  858.                 if (FrontWindow() == gameWindow)
  859.                 {
  860.                     DrawScoreBar();
  861.                     if ((gameOver) || (gamePaused))
  862.                     {
  863.                         DrawContent();
  864.                     }
  865.                     if (gameOver)
  866.                     {
  867.                         WriteGameOver();
  868.                     }
  869.                     DrawControls(gameWindow);
  870.                 }
  871.                 EndUpdate((GrafPtr) event.message);
  872.                 SetPort(oldPort);
  873.             }
  874.             break;
  875.         default:
  876.             break;
  877.     }
  878. }
  879.  
  880. DoIdle(void)
  881. {
  882.     if ((!gamePaused) && (!gameOver))
  883.     {
  884.         if ((TickCount() - lastTicks) >= TICK_DELAY)
  885.         {
  886.             Animate();
  887.             lastTicks = TickCount();
  888.         }
  889.     }
  890. }
  891.  
  892. DoMouseDown(EventRecord event)
  893. {
  894.     WindowPtr    whichWindow;
  895.     
  896.     switch (FindWindow(event.where, &whichWindow))
  897.     {
  898.         case inMenuBar:
  899.             AdjustMenus();
  900.             DoMenuChoice(MenuSelect(event.where));
  901.             break;
  902.         case inSysWindow:
  903.             SystemClick(&event, whichWindow);
  904.             break;
  905.         case inDrag:
  906.             DragWindow(whichWindow, event.where, &gDragRect);
  907.             break;
  908.         case inContent:
  909.             SelectWindow(whichWindow);
  910.             if ((!gamePaused) && (!gameOver))
  911.             {
  912.                 HandleInContent(event.where);
  913.             }
  914.             if (gameOver)
  915.             {
  916.                 DoGameOverButtons(event.where);
  917.             }
  918.             break;
  919.         default:
  920.             break;
  921.     }
  922. }
  923.  
  924. AdjustMenus(void)
  925. {
  926.     if (IsDAWindow(FrontWindow()))
  927.     {
  928.         EnableItem(gEditMenu, UNDO_ITEM);
  929.         EnableItem(gEditMenu, CUT_ITEM);
  930.         EnableItem(gEditMenu, PASTE_ITEM);
  931.         EnableItem(gEditMenu, COPY_ITEM);
  932.         EnableItem(gEditMenu, CLEAR_ITEM);
  933.     }
  934.     else
  935.     {
  936.         DisableItem(gEditMenu, UNDO_ITEM);
  937.         DisableItem(gEditMenu, CUT_ITEM);
  938.         DisableItem(gEditMenu, PASTE_ITEM);
  939.         DisableItem(gEditMenu, COPY_ITEM);
  940.         DisableItem(gEditMenu, CLEAR_ITEM);
  941.     }
  942.     
  943.     if (gameOver)
  944.     {
  945.         DisableItem(gFileMenu, PAUSE_RESUME_ITEM);
  946.         DisableItem(gFileMenu, STOP_ITEM);
  947.     }
  948.     else
  949.     {
  950.         EnableItem(gFileMenu, PAUSE_RESUME_ITEM);
  951.         EnableItem(gFileMenu, STOP_ITEM);        
  952.     }
  953.     
  954.     if (gamePaused)
  955.     {
  956.         SetItem(gFileMenu, PAUSE_RESUME_ITEM, "\pResume");
  957.     }
  958.     else
  959.     {
  960.         SetItem(gFileMenu, PAUSE_RESUME_ITEM, "\pPause");
  961.     }        
  962. }
  963.  
  964. IsDAWindow(WindowPtr whichWindow)
  965. {
  966.     if (whichWindow == NULL)
  967.     {
  968.         return (FALSE);
  969.     }
  970.     else
  971.     {
  972.         return (((WindowPeek) whichWindow)->windowKind < 0);
  973.     }
  974. }
  975.  
  976. DoMenuChoice(long selection)
  977. {
  978.     int    menu;
  979.     int    item;
  980.     
  981.     if (selection != 0)
  982.     {
  983.         menu = HiWord(selection);
  984.         item = LoWord(selection);
  985.         switch (menu)
  986.         {
  987.             case APPLE_MENU_ID:
  988.                 DoAppleChoice(item);
  989.                 break;
  990.             case FILE_MENU_ID:
  991.                 DoFileChoice(item);
  992.             case EDIT_MENU_ID:
  993.                 DoEditChoice(item);
  994.                 break;
  995.             case GAME_MENU_ID:
  996.                 DoGameChoice(item);
  997.                 break;
  998.             default:
  999.                 break;
  1000.         }
  1001.         HiliteMenu(0);
  1002.     }
  1003. }
  1004.  
  1005. DoAppleChoice(int item)
  1006. {
  1007.     Str255    accName;
  1008.     GrafPtr    oldPort;
  1009.     
  1010.     switch (item)
  1011.     {
  1012.         case ABOUT_ITEM:
  1013.             AboutDialog();
  1014.             break;
  1015.         default:
  1016.             GetItem(gAppleMenu, item, accName);
  1017.             GetPort(&oldPort);
  1018.             (void) OpenDeskAcc(accName);
  1019.             SetPort(oldPort);
  1020.             break;
  1021.     }
  1022. }
  1023.  
  1024. DoFileChoice(int item)
  1025. {
  1026.     switch (item)
  1027.     {
  1028.         case NEW_GAME_ITEM:
  1029.             SetUpGame();
  1030.             break;
  1031.         case PAUSE_RESUME_ITEM:
  1032.             if (!gamePaused)
  1033.             {
  1034.                 gamePaused = TRUE;
  1035.             }
  1036.             else
  1037.             {
  1038.                 gamePaused = FALSE;        
  1039.                 GetDateTime(&lastTime);
  1040.             }        
  1041.             break;
  1042.         case STOP_ITEM:
  1043.             EndGame();
  1044.             break;
  1045.         case QUIT_ITEM:
  1046.             gDone = TRUE;
  1047.             break;
  1048.         default:
  1049.             break;
  1050.     }
  1051. }
  1052.  
  1053. DoEditChoice(int item)
  1054. {
  1055.     SystemEdit(item - 1);
  1056. }
  1057.  
  1058. DoGameChoice(int item)
  1059. {
  1060.     switch (item)
  1061.     {
  1062.         case GAME_OPTIONS_ITEM:
  1063.             GameOptionsDialog();
  1064.             break;
  1065.         case ANIMAL_POINT_VALUES_ITEM:
  1066.             AnimalPointValuesDialog();
  1067.             break;
  1068.         case HALL_OF_FAME_ITEM:
  1069.             HallOfFameDialog();
  1070.             break;
  1071.         default:
  1072.             break;
  1073.     }
  1074. }
  1075.  
  1076. HandleInContent(Point where)
  1077. {
  1078.     register int    i;
  1079.     int                h, v;
  1080.     RgnHandle        animalRgn;
  1081.     
  1082.     GlobalToLocal(&where);
  1083.     
  1084.     for (i = 0; i < animalRows; i++)
  1085.     {
  1086.         if (PtInRect(where, &row[i].rect))
  1087.         {
  1088.             if (!easyShoot)
  1089.             {
  1090.                 animalRgn = (RgnHandle) GetResource('RGN ', animal[row[i].animal].region[row[i].step]);
  1091.                 
  1092.                 h = row[i].rect.right - (**animalRgn).rgnBBox.right;
  1093.                 v = row[i].rect.bottom - (**animalRgn).rgnBBox.bottom;
  1094.             
  1095.                 OffsetRgn(animalRgn, h, v);
  1096.                 
  1097.                 if (PtInRgn(where, animalRgn)) 
  1098.                 {
  1099.                     PaintRgn(animalRgn);
  1100.                     DoSound(BASE_RES_ID + row[i].animal, TRUE);
  1101.                     AnimalShot(i);
  1102.                 }
  1103.             }    
  1104.             else
  1105.             {
  1106.                 DoSound(BASE_RES_ID + row[i].animal, TRUE);
  1107.                 AnimalShot(i);
  1108.             }    
  1109.         }
  1110.     }
  1111. }
  1112.  
  1113. DoGameOverButtons(Point where)
  1114. {
  1115.     ControlHandle    whichControl;
  1116.     
  1117.     GlobalToLocal(&where);
  1118.     
  1119.     (void) FindControl(where, gameWindow, &whichControl);
  1120.     
  1121.     if (whichControl != NULL)
  1122.     {
  1123.         if (TrackControl(whichControl, where, NULL) != 0)
  1124.         {
  1125.             if (whichControl == playAgainControl)
  1126.             {
  1127.                 SetUpGame();
  1128.             }
  1129.             if (whichControl == quitControl)
  1130.             {
  1131.                 ExitToShell();
  1132.             }
  1133.         }
  1134.     }
  1135. }
  1136.  
  1137. AnimalShot(int i)
  1138. {
  1139.     Str255    scoreString;
  1140.     int        length;
  1141.     Rect    scoreRect;
  1142.     
  1143.     gameScore += animal[row[i].animal].value;
  1144.     length = StringWidth("\pScore: ") + 2;
  1145.     SetRect(&scoreRect, length, 0, length + StringWidth("\p000000"), 20);
  1146.     EraseRect(&scoreRect);
  1147.     MoveTo(length, 17);
  1148.     NumToString(gameScore, scoreString);
  1149.     DrawString(scoreString);
  1150.         
  1151.     EraseRect(&row[i].rect);
  1152.     row[i].rect.left = 0;
  1153.     row[i].rect.right = 33;
  1154.        row[i].running = FALSE;
  1155.        
  1156.        if (increaseSpeed)
  1157.        {
  1158.         speedIncrease = gameScore / 1000;
  1159.     }
  1160. }
  1161.  
  1162. ErrorHandler(int stringNum)
  1163. {
  1164.     StringHandle    errorStringH;
  1165.     
  1166.     if ((errorStringH = GetString(stringNum)) == NULL)
  1167.     {
  1168.         ParamText(HOPELESSLY_FATAL_ERROR, NULL, NULL, NULL);
  1169.     }
  1170.     else
  1171.     {
  1172.         MoveHHi((Handle) errorStringH);
  1173.         HLock((Handle) errorStringH);
  1174.         ParamText(*errorStringH, NULL, NULL, NULL);
  1175.         HUnlock((Handle) errorStringH);
  1176.     }
  1177.     StopAlert(ERROR_ALERT_ID, NULL);
  1178.     ExitToShell();
  1179. }
  1180.  
  1181. Animate(void)
  1182. {
  1183.     int        r;
  1184.     Rect    copyRect;
  1185.     GrafPtr    secondOffScreen;
  1186.     
  1187.     /* Open loop goes from 0 to animalRows - 1 & allows for WaitNextEvent to occur
  1188.         between each animal drawing */
  1189.     
  1190.     loopValue %= animalRows;
  1191.     
  1192.     if (!row[loopValue].running)
  1193.     {
  1194.         row[loopValue].running = TRUE;
  1195.         r = Randomize(9);
  1196.         row[loopValue].animal = r;
  1197.         row[loopValue].speed = animal[r].speed;
  1198.         row[loopValue].step = 0;
  1199.     }
  1200.     
  1201.     row[loopValue].step = (row[loopValue].step == 1) ? 0 : 1;
  1202.     
  1203.     OffsetRect(&row[loopValue].rect,
  1204.         row[loopValue].speed * speedFactor + speedIncrease, 0);
  1205.  
  1206.     SetRect(©Rect,
  1207.         row[loopValue].rect.left - (row[loopValue].speed * speedFactor + speedIncrease),
  1208.         row[loopValue].rect.top,
  1209.         row[loopValue].rect.right,
  1210.         row[loopValue].rect.bottom);
  1211.  
  1212.     if (!CreateOffscreenBitMap(&secondOffScreen, ©Rect)) 
  1213.     {
  1214.         SysBeep(1);
  1215.         ExitToShell();
  1216.      }
  1217.       SetPort(secondOffScreen);
  1218.        EraseRect(©Rect);
  1219.            
  1220.        CopyBits(&offscreen->portBits, &secondOffScreen->portBits, 
  1221.            &animal[row[loopValue].animal].rect[row[loopValue].step], &row[loopValue].rect, srcCopy, NULL);
  1222.        SetPort(gameWindow);
  1223.        CopyBits(&secondOffScreen->portBits, &gameWindow->portBits,
  1224.            ©Rect, ©Rect, srcCopy, NULL);
  1225.        DestroyOffscreenBitMap(secondOffScreen);
  1226.  
  1227.        if (row[loopValue].rect.left >= windowWidth)
  1228.        {
  1229.         row[loopValue].rect.left = 0;
  1230.         row[loopValue].rect.right = 33;
  1231.            row[loopValue].running = FALSE;
  1232.            if (escapedGame)
  1233.            {
  1234.              AnimalEscaped();
  1235.          }
  1236.        }
  1237.  
  1238.     loopValue++;
  1239.     if (!escapedGame)
  1240.     {
  1241.         PostTimeRemaining();
  1242.     }
  1243. }
  1244.  
  1245. DrawContent(void)
  1246. {
  1247.     GrafPtr            oldPort;
  1248.     register int    i;
  1249.     
  1250.     GetPort(&oldPort);
  1251.     SetPort(gameWindow);
  1252.  
  1253.     for (i = 0; i < animalRows; i++)
  1254.     {
  1255.            CopyBits(&offscreen->portBits, &gameWindow->portBits,
  1256.              &animal[row[i].animal].rect[row[i].step], &row[i].rect,srcCopy, NULL);
  1257.      }
  1258.     SetPort(oldPort);
  1259. }
  1260.  
  1261. Randomize(int range)
  1262. {
  1263.      long    rawResult = Random();
  1264.      
  1265.      if (rawResult < 0)
  1266.      {
  1267.          rawResult *= -1;
  1268.      }
  1269.      return (rawResult % range);
  1270. }
  1271.  
  1272. AnimalEscaped(void)
  1273. {
  1274.     int        length = StringWidth("\p000") + 2;
  1275.     Rect    escapedRect;
  1276.      Str255    scoreString;
  1277.         
  1278.     animalsEscaped++;
  1279.     SetRect(&escapedRect, windowWidth - length, 0, windowWidth, 20);
  1280.     MoveTo(windowWidth - length, 17);
  1281.     NumToString(animalsEscaped, scoreString);
  1282.     EraseRect(&escapedRect);
  1283.     DrawString(scoreString);
  1284.     if ((escapedGame) && (maxEscaped <= animalsEscaped))
  1285.     {
  1286.         EndGame();
  1287.     }
  1288. }
  1289.  
  1290.  
  1291. WriteGameOver(void)
  1292. {
  1293.     int        length = StringWidth("\pGame Over");
  1294.     Rect    myRect;
  1295.     
  1296.     SetRect(&myRect, windowWidth / 2 - length / 2 - 2, windowHeight / 2 - 10, 
  1297.             windowWidth / 2 + length / 2 + 2, windowHeight / 2 + 10);
  1298.     EraseRect(&myRect);
  1299.     MoveTo(windowWidth / 2 - length / 2, windowHeight / 2);
  1300.     DrawString("\pGame Over");
  1301. }
  1302.  
  1303. EndOfGameControls(void)
  1304. {
  1305.     ShowControl(playAgainControl);
  1306.     ShowControl(quitControl);
  1307. }
  1308.  
  1309. EndGame(void)
  1310. {
  1311.     gameOver = TRUE;
  1312.     WriteGameOver();
  1313.     EndOfGameControls();
  1314.     if ((gameScore >= topScores[2]) && (showHighScores))
  1315.     {
  1316.         UpdateHighScores();
  1317.     }
  1318. }
  1319.  
  1320. UpdateHighScores(void)
  1321. {
  1322.     register int    i;
  1323.     StringHandle    theString, topNames[3];
  1324.     Str255            numString;
  1325.     
  1326.     GetPlayerName();
  1327.     
  1328.     for (i = 0; i <= 2; i++)
  1329.     {
  1330.         if ((theString = GetString(HIGH_NAMES_STRING + i)) == NULL)
  1331.         {
  1332.             ErrorHandler(NO_STR);
  1333.         }
  1334.         MoveHHi((Handle) theString);
  1335.         HLock((Handle) theString);    
  1336.         topNames[i] = theString;
  1337.         HUnlock((Handle) theString);    
  1338.     }
  1339.         
  1340.     if (gameScore >= topScores[0])
  1341.     {
  1342.         topScores[2] = topScores[1];
  1343.         SetString(topNames[2], *topNames[1]);
  1344.         topScores[1] = topScores[0];
  1345.         SetString(topNames[1], *topNames[0]);
  1346.         topScores[0] = gameScore;
  1347.         SetString(topNames[0], name);
  1348.     }
  1349.     else if (gameScore >= topScores[1])
  1350.     {
  1351.         topScores[2] = topScores[1];
  1352.         SetString(topNames[2], *topNames[1]);
  1353.         topScores[1] = gameScore;
  1354.         SetString(topNames[1], name);
  1355.     }
  1356.     else
  1357.     {
  1358.         topScores[2] = gameScore;
  1359.         SetString(topNames[2], name);
  1360.     }
  1361.     
  1362.     for (i = 0; i <= 2; i++)
  1363.     {
  1364.         if ((theString = GetString(HIGH_NAMES_STRING + i)) == NULL)
  1365.         {
  1366.             ErrorHandler(NO_STR);
  1367.         }
  1368.         MoveHHi((Handle) theString);
  1369.         HLock((Handle) theString);
  1370.         SetString(theString, *topNames[i]);
  1371.         ChangedResource((Handle) theString);
  1372.         WriteResource((Handle) theString);
  1373.         HUnlock((Handle) theString);
  1374.         
  1375.         if ((theString = GetString(HIGH_SCORE_STRING + i)) == NULL)
  1376.         {
  1377.             ErrorHandler(NO_STR);
  1378.         }
  1379.         NumToString(topScores[i], numString);
  1380.         SetString(theString, numString);
  1381.         ChangedResource((Handle) theString);
  1382.         WriteResource((Handle) theString);
  1383.     }
  1384.     
  1385.     HallOfFameDialog();
  1386. }
  1387.  
  1388. GetPlayerName(void)
  1389. {
  1390.     GrafPtr         savePort;
  1391.     int                stringNum = 502 - (gameScore >= topScores[1]) - (gameScore >= topScores[0]);
  1392.     StringHandle    whichString;
  1393.     DialogPtr        theDialog;
  1394.     int                itemHit;
  1395.     int                itemType;
  1396.     Handle            itemHandle;
  1397.     Rect            itemRect;
  1398.     Boolean            dialogDone = FALSE;
  1399.     
  1400.     GetPort(&savePort);
  1401.  
  1402.     if ((whichString = GetString(stringNum)) == NULL)
  1403.     {
  1404.         ParamText(HOPELESSLY_FATAL_ERROR, NULL, NULL, NULL);
  1405.     }
  1406.     MoveHHi((Handle) whichString);
  1407.     HLock((Handle) whichString);
  1408.     ParamText(*whichString, NULL, NULL, NULL);
  1409.     HUnlock((Handle) whichString);
  1410.     if ((theDialog = GetNewDialog(PLAYER_NAME_DIALOG, NULL, M_T_F)) == NULL)
  1411.     {
  1412.         ErrorHandler(NO_WIND);
  1413.     }
  1414.     SelIText(theDialog, PLAYER_NAME_ITEXT, 0, 255);
  1415.     CenterWindow(theDialog);
  1416.     ShowWindow(theDialog);
  1417.     
  1418.     SetPort(theDialog);
  1419.     
  1420.     SetCursor(&arrow);
  1421.     
  1422.     DoSound(TARZAN_SOUND, TRUE);
  1423.     
  1424.     while (!dialogDone)
  1425.     {
  1426.         ModalDialog(NULL, &itemHit);
  1427.         switch (itemHit)
  1428.         {
  1429.             case OK_BUTTON:
  1430.                 dialogDone = TRUE;
  1431.                 break;
  1432.             default:
  1433.                 break;
  1434.         }
  1435.     }
  1436.     
  1437.     GetDItem(theDialog, PLAYER_NAME_ITEXT, &itemType, &itemHandle, &itemRect);
  1438.     MoveHHi((Handle) itemHandle);
  1439.     HLock(itemHandle);
  1440.     GetIText(itemHandle, name);
  1441.     HUnlock(itemHandle);
  1442.     
  1443.     DisposDialog(theDialog);
  1444.     SetPort(savePort);
  1445. }
  1446.  
  1447. AnimalPointValuesDialog(void)
  1448. {    
  1449.     GrafPtr        savePort;
  1450.     DialogPtr    theDialog;
  1451.     Boolean        dialogDone = FALSE;
  1452.     int            itemHit;
  1453.  
  1454.     GetPort(&savePort);
  1455.     
  1456.     if ((theDialog = GetNewDialog(ANIMAL_POINT_VALUES_DIALOG, NULL, M_T_F)) == NULL)
  1457.     {
  1458.         ErrorHandler(NO_WIND);
  1459.     }
  1460.     CenterWindow(theDialog);
  1461.     ShowWindow(theDialog);
  1462.     
  1463.     SetPort(theDialog);
  1464.     
  1465.     while (!dialogDone)
  1466.     {
  1467.         ModalDialog(NULL, &itemHit);
  1468.         switch (itemHit - 1)
  1469.         {
  1470.             case RHINO:
  1471.             case ELEPHANT:
  1472.             case ZEBRA:
  1473.             case GORILLA:
  1474.             case ANTELOPE:
  1475.             case GIRAFFE:
  1476.             case LION:
  1477.             case CHEETAH:
  1478.             case WARTHOG:    
  1479.                 DoSound(BASE_RES_ID + itemHit - 1, TRUE);
  1480.                 break;
  1481.             case OK_APV_DBOX:
  1482.                 dialogDone = TRUE;
  1483.                 break;
  1484.             default:
  1485.                 break;
  1486.         }
  1487.     }
  1488.     DisposDialog(theDialog);
  1489.     SetPort(savePort);
  1490. }
  1491.  
  1492. AboutDialog(void)
  1493. {    
  1494.     GrafPtr     savePort;
  1495.     DialogPtr    theDialog;
  1496.     int            itemType;
  1497.     Handle        itemHandle;
  1498.     Rect        itemRect;
  1499.     Boolean        dialogDone = FALSE;
  1500.     int            itemHit;
  1501.     
  1502.     #define ICON_ITEM    5
  1503.  
  1504.     GetPort(&savePort);
  1505.     
  1506.     if ((theDialog = GetNewDialog(ABOUT_DIALOG, NULL, M_T_F)) == NULL)
  1507.     {
  1508.         ErrorHandler(NO_WIND);
  1509.     }
  1510.     CenterWindow(theDialog);
  1511.     ShowWindow(theDialog);
  1512.     
  1513.     SetPort(theDialog);
  1514.     
  1515.     GetDItem(theDialog, ICON_ITEM, &itemType, &itemHandle, &itemRect);
  1516.     PlotIcon(&itemRect, GetIcon(MY_HEAD));
  1517.     
  1518.     while (!dialogDone)
  1519.     {
  1520.         ModalDialog(NULL, &itemHit);
  1521.         switch (itemHit)
  1522.         {
  1523.             case OK_BUTTON:
  1524.                 dialogDone = TRUE;
  1525.                 break;
  1526.             case SHOW_INTRO_SCREEN:
  1527.                 IntroDialog();
  1528.                 break;
  1529.             case HEAD_ICON:
  1530.                 PlotIcon(&itemRect, GetIcon(OUCH_HEAD));
  1531.                 DoSound(OUCH_SOUND, FALSE);
  1532.                 PlotIcon(&itemRect, GetIcon(MY_HEAD));
  1533.                 break;
  1534.             default:
  1535.                 break;
  1536.         }
  1537.     }
  1538.     DisposDialog(theDialog);
  1539.     SetPort(savePort);
  1540. }
  1541.  
  1542. HallOfFameDialog(void)
  1543. {    
  1544.     GrafPtr         savePort;
  1545.     DialogPtr        theDialog;
  1546.     register int    i;
  1547.     StringHandle    theString;
  1548.     int                itemType;
  1549.     Handle            itemHandle;
  1550.     Rect            itemRect;
  1551.     Boolean         dialogDone = FALSE;
  1552.     int                itemHit;
  1553.     
  1554.     GetPort(&savePort);
  1555.     
  1556.     if ((theDialog = GetNewDialog(HALL_OF_FAME_DIALOG, NULL, M_T_F)) == NULL)
  1557.     {
  1558.         ErrorHandler(NO_WIND);
  1559.     }
  1560.     for (i = 0; i <= 5; i++)
  1561.     {
  1562.         if ((theString = GetString(128 + i)) == NULL)
  1563.         {
  1564.             ErrorHandler(NO_STR);
  1565.         }
  1566.         MoveHHi((Handle) theString);
  1567.         HLock((Handle) theString);    
  1568.         GetDItem(theDialog, i + 3, &itemType, &itemHandle, &itemRect);
  1569.         SetIText(itemHandle, *theString);
  1570.         HUnlock((Handle) theString);    
  1571.     }
  1572.     CenterWindow(theDialog);
  1573.     ShowWindow(theDialog);
  1574.     
  1575.     SetPort(theDialog);
  1576.     
  1577.     while (!dialogDone)
  1578.     {
  1579.         ModalDialog(NULL, &itemHit);
  1580.         switch (itemHit)
  1581.         {
  1582.             case OK_BUTTON:
  1583.                 dialogDone = TRUE;
  1584.                 break;
  1585.             case CLEAR_SCORES_BUTTON:
  1586.                 dialogDone = TRUE;
  1587.                 ClearHighScores();
  1588.                 break;
  1589.             default:
  1590.                 break;
  1591.         }
  1592.     }
  1593.     DisposDialog(theDialog);
  1594.     SetPort(savePort);
  1595. }
  1596.  
  1597. ClearHighScores(void)
  1598. {
  1599.     register int    i;
  1600.     StringHandle    theString;
  1601.     
  1602.     for (i = 0; i <= 2; i++)
  1603.     {
  1604.         if ((theString = GetString(HIGH_SCORE_STRING + i)) == NULL)
  1605.         {
  1606.             ErrorHandler(NO_STR);
  1607.         }
  1608.         HNoPurge((Handle) theString);
  1609.         SetString(theString, "\p0"); 
  1610.         ChangedResource((Handle) theString);
  1611.         WriteResource((Handle) theString);
  1612.         HPurge((Handle) theString);
  1613.         
  1614.         if ((theString = GetString(HIGH_NAMES_STRING + i)) == NULL)
  1615.         {
  1616.             ErrorHandler(NO_STR);
  1617.         }
  1618.         HNoPurge((Handle) theString);
  1619.         SetString(theString, "\pPlayer Name"); 
  1620.         ChangedResource((Handle) theString);
  1621.         WriteResource((Handle) theString);
  1622.         HPurge((Handle) theString);
  1623.         topScores[i] = 0;
  1624.     }
  1625. }
  1626.  
  1627. Boolean CheckITextValues(DialogPtr theDialog)
  1628. {
  1629.     register int    i;
  1630.     int                itemType;
  1631.     Handle            itemHandle;
  1632.     Rect            itemRect;
  1633.     long            stringValue;
  1634.     Boolean            dialogDone = TRUE;
  1635.     
  1636.     for (i = MINUTES; i <= MAX_ESCAPED; i++)
  1637.     {
  1638.         GetDItem(theDialog, i, &itemType, &itemHandle, &itemRect);
  1639.         MoveHHi((Handle) itemHandle);
  1640.         HLock(itemHandle);
  1641.         GetIText(itemHandle, preferenceString[i]);
  1642.         HUnlock(itemHandle);
  1643.     }
  1644.  
  1645.     StringToNum(preferenceString[MINUTES], &stringValue);
  1646.     if ((stringValue < 0) || (stringValue > 99))
  1647.     {
  1648.         BadValue(MINUTES_ERROR);
  1649.         SelIText(theDialog, MINUTES, 0, 255);
  1650.         dialogDone = FALSE;
  1651.     }
  1652.     
  1653.     StringToNum(preferenceString[SECONDS], &stringValue);
  1654.     if ((stringValue < 0) || (stringValue > 59))
  1655.     {
  1656.         BadValue(SECONDS_ERROR);
  1657.         SelIText(theDialog, SECONDS, 0, 255);
  1658.         dialogDone = FALSE;
  1659.     }
  1660.     
  1661.     StringToNum(preferenceString[MAX_ESCAPED], &stringValue);
  1662.     if ((stringValue < 1) || (stringValue > 99))
  1663.     {
  1664.         BadValue(ESCAPED_ERROR);
  1665.         SelIText(theDialog, MAX_ESCAPED, 0, 255);
  1666.         dialogDone = FALSE;
  1667.     }
  1668.     
  1669.     return (dialogDone);
  1670. }
  1671.  
  1672. CheckHighScoreDisplay(void)
  1673. {
  1674.     register int    i;
  1675.     StringHandle    theString;
  1676.     long            savedValues[8], preferenceValue[8];
  1677.     
  1678.     showHighScores = TRUE;
  1679.     
  1680.     for (i = 0; i <= 7; i++)
  1681.     {
  1682.         if ((theString = GetString(200 + i)) == NULL)
  1683.         {
  1684.             ErrorHandler(NO_STR);
  1685.         }
  1686.         MoveHHi((Handle) theString);
  1687.         HLock((Handle) theString);    
  1688.         StringToNum(*theString , &savedValues[i]);    
  1689.         HUnlock((Handle) theString);
  1690.         StringToNum(preferenceString[i], &preferenceValue[i]);
  1691.     }
  1692.     
  1693.     for (i = 0; i <= 4; i++)
  1694.     {
  1695.         if (savedValues[i] != preferenceValue[i])
  1696.         {
  1697.             showHighScores = FALSE;
  1698.         }
  1699.     }
  1700.  
  1701.     if (showHighScores)
  1702.     {
  1703.         switch (savedValues[TIMED_OR_ESCAPED - 200])
  1704.         {
  1705.             case TIMED_RADIO:
  1706.                 if (savedValues[MINUTES_STRING - 200] != preferenceValue[MINUTES_STRING - 200])
  1707.                 {
  1708.                     showHighScores = FALSE;
  1709.                 }
  1710.                 if (savedValues[SECONDS_STRING - 200] != preferenceValue[SECONDS_STRING - 200])
  1711.                 {
  1712.                     showHighScores = FALSE;
  1713.                 }
  1714.                 break;
  1715.             case ESCAPED_RADIO:
  1716.                 if (savedValues[MAX_ESCAPED_STRING - 200] != preferenceValue[MAX_ESCAPED_STRING - 200])
  1717.                 {
  1718.                     showHighScores = FALSE;
  1719.                 }
  1720.                 break;
  1721.             default:
  1722.                 break;
  1723.         }    
  1724.     }
  1725.     
  1726.     if (showHighScores)
  1727.     {
  1728.         GetHighScores();
  1729.     }
  1730. }
  1731.  
  1732. GameOptionsDialog(void)
  1733. {
  1734.     GrafPtr        savePort;
  1735.     DialogPtr    theDialog;
  1736.     Boolean        dialogDone = FALSE;
  1737.     int            itemHit;
  1738.     int            itemType;
  1739.     Handle        itemHandle;
  1740.     Rect        itemRect;
  1741.  
  1742.     GetPort(&savePort);
  1743.  
  1744.     if ((theDialog = GetNewDialog(GAME_OPTIONS_DIALOG, NULL, M_T_F)) == NULL)
  1745.     {
  1746.         ErrorHandler(NO_WIND);
  1747.     }
  1748.     DialogInit(theDialog);
  1749.     CenterWindow(theDialog);
  1750.     ShowWindow(theDialog);
  1751.     
  1752.     while (!dialogDone)
  1753.     {
  1754.         ModalDialog((ProcPtr) &GameOptionsDProc, &itemHit);
  1755.         switch (itemHit)
  1756.         {
  1757.             case OK_BUTTON:
  1758.                 dialogDone = CheckITextValues(theDialog);
  1759.                 if (dialogDone)
  1760.                 {
  1761.                     showHighScores = FALSE;
  1762.                     CheckHighScoreDisplay();
  1763.                     SetUpGame();
  1764.                 }
  1765.                 break;
  1766.             case SAVE_AND_CLEAR_BUTTON:
  1767.                 dialogDone = CheckITextValues(theDialog);
  1768.                 if (dialogDone)
  1769.                 {
  1770.                     UpdatePreferences(theDialog);    
  1771.                     ClearHighScores();
  1772.                     showHighScores = TRUE;
  1773.                     SetUpGame();
  1774.                 }
  1775.                 break;
  1776.             case CANCEL_BUTTON:
  1777.                 dialogDone = TRUE;
  1778.                 break;
  1779.             case TIMED_RADIO:
  1780.             case ESCAPED_RADIO:
  1781.                 GetDItem(theDialog, TIMED_RADIO, &itemType, &itemHandle, &itemRect);
  1782.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == TIMED_RADIO));
  1783.                 GetDItem(theDialog, ESCAPED_RADIO, &itemType, &itemHandle, &itemRect);
  1784.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == ESCAPED_RADIO));
  1785.                 NumToString(itemHit, preferenceString[TIMED_OR_ESCAPED - 200]);
  1786.                 break;
  1787.             case SPEED_POP_UP:
  1788.                 GetDItem(theDialog, SPEED_POP_UP, &itemType, &itemHandle, &itemRect);
  1789.                 itemHit = GetCtlValue((ControlHandle) itemHandle);
  1790.                 NumToString(itemHit + 24, preferenceString[ANIMAL_SPEED - 200]);
  1791.                 break;
  1792.             case NINE_INCH_RADIO:
  1793.             case CURRENT_SCREEN_RADIO:
  1794.                 GetDItem(theDialog, NINE_INCH_RADIO, &itemType, &itemHandle, &itemRect);
  1795.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == NINE_INCH_RADIO));
  1796.                 GetDItem(theDialog, CURRENT_SCREEN_RADIO, &itemType, &itemHandle, &itemRect);
  1797.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == CURRENT_SCREEN_RADIO));
  1798.                 NumToString(itemHit, preferenceString[WINDOW_SIZE - 200]);
  1799.                 break;
  1800.             case INCREASE_YES_RADIO:
  1801.             case INCREASE_NO_RADIO:
  1802.                 GetDItem(theDialog, INCREASE_YES_RADIO, &itemType, &itemHandle, &itemRect);
  1803.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == INCREASE_YES_RADIO));
  1804.                 GetDItem(theDialog, INCREASE_NO_RADIO, &itemType, &itemHandle, &itemRect);
  1805.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == INCREASE_NO_RADIO));
  1806.                 NumToString(itemHit, preferenceString[INCREASE_SPEED - 200]);
  1807.                 break;
  1808.             case IN_ANIMAL_OUTLINE_RADIO:
  1809.             case IN_BOX_SURROUNDING_ANIMAL_RADIO:
  1810.                 GetDItem(theDialog, IN_ANIMAL_OUTLINE_RADIO, &itemType, &itemHandle, &itemRect);
  1811.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == IN_ANIMAL_OUTLINE_RADIO));
  1812.                 GetDItem(theDialog, IN_BOX_SURROUNDING_ANIMAL_RADIO, &itemType, &itemHandle, &itemRect);
  1813.                 SetCtlValue((ControlHandle) itemHandle, (itemHit == IN_BOX_SURROUNDING_ANIMAL_RADIO));
  1814.                 NumToString(itemHit, preferenceString[SCORE_WHEN_HIT - 200]);
  1815.                 break;
  1816.             default:
  1817.                 break;
  1818.         }
  1819.     }
  1820.     
  1821.     DisposDialog(theDialog);
  1822.     SetPort(savePort);
  1823. }
  1824.  
  1825. pascal Boolean GameOptionsDProc(DialogPtr theDialog, EventRecord *theEvent, int *itemHit)
  1826. {
  1827.     int            itemType;
  1828.     Handle        itemHandle;
  1829.     Rect        itemRect;
  1830.  
  1831.     switch (theEvent->what)
  1832.     {
  1833.         case updateEvt:
  1834.             if (IsDialogEvent(theEvent))
  1835.             {
  1836.                 SetPort(theDialog);
  1837.                 GetDItem(theDialog, 25, &itemType, &itemHandle, &itemRect);
  1838.                 FrameRect(&itemRect);
  1839.                 GetDItem(theDialog, 26, &itemType, &itemHandle, &itemRect);
  1840.                 FrameRect(&itemRect);
  1841.                 GetDItem(theDialog, 27, &itemType, &itemHandle, &itemRect);
  1842.                 FrameRect(&itemRect);
  1843.             }
  1844.             return (FALSE);
  1845.             break;
  1846.         default:
  1847.             return (FALSE);
  1848.             break;
  1849.     }
  1850. }
  1851.  
  1852. UpdatePreferences(DialogPtr theDialog)
  1853. {
  1854.     register int    i;
  1855.     StringHandle    theString;
  1856.     
  1857.     for (i = 200; i <= 214; i += (i == 204) ? 8 : 1)
  1858.     {
  1859.         if ((theString = GetString(i)) == NULL)
  1860.         {
  1861.             ErrorHandler(NO_STR);
  1862.         }
  1863.         HNoPurge((Handle) theString);
  1864.         SetString(theString, preferenceString[i - 200]); 
  1865.         ChangedResource((Handle) theString);
  1866.         WriteResource((Handle) theString);
  1867.         HPurge((Handle) theString);
  1868.     }
  1869. }
  1870.  
  1871. DialogInit(DialogPtr theDialog)
  1872. {
  1873.     register int    i;
  1874.     StringHandle    theString;
  1875.     long            itemNumber;
  1876.     int                itemType;
  1877.     Handle            itemHandle;
  1878.     Rect            itemRect;
  1879.  
  1880.     for (i = TIMED_OR_ESCAPED; i <= SCORE_WHEN_HIT; i++)
  1881.     {
  1882.         if ((theString = GetString(i)) == NULL)
  1883.         {
  1884.             ErrorHandler(NO_STR);
  1885.         }
  1886.         MoveHHi((Handle) theString);
  1887.         HLock((Handle) theString);    
  1888.         StringToNum(*theString, &itemNumber);
  1889.         if ((itemNumber == SLOW_RADIO) || (itemNumber == MEDIUM_RADIO) || 
  1890.             (itemNumber == FAST_RADIO))
  1891.         {
  1892.             GetDItem(theDialog, SPEED_POP_UP, &itemType, &itemHandle, &itemRect);
  1893.             SetCtlValue((ControlHandle) itemHandle, itemNumber - 24);
  1894.         }
  1895.         else
  1896.         {
  1897.             GetDItem(theDialog, itemNumber, &itemType, &itemHandle, &itemRect);
  1898.             SetCtlValue((ControlHandle) itemHandle, TRUE);
  1899.         }
  1900.         NumToString(itemNumber, preferenceString[i - 200]);
  1901.         HUnlock((Handle) theString);
  1902.     }
  1903.  
  1904.     for (i = MINUTES_STRING; i <= MAX_ESCAPED_STRING; i++)
  1905.     {
  1906.         if ((theString = GetString(i)) == NULL)
  1907.         {
  1908.             ErrorHandler(NO_STR);
  1909.         }
  1910.         MoveHHi((Handle) theString);
  1911.         HLock((Handle) theString);    
  1912.         GetDItem(theDialog, i - 200, &itemType, &itemHandle, &itemRect);
  1913.         SetIText(itemHandle, *theString);
  1914. /*
  1915.         item number is just a place holder in the next two lines (it's significant
  1916.         as the item number in all other code) I couldn't get the string handle
  1917.         to equate to the string, so this is my work around. I make the string
  1918.         handle a number, then make the number a string.  Ugly but functional.
  1919. */
  1920.         StringToNum(*theString, &itemNumber);
  1921.         NumToString(itemNumber, preferenceString[i - 200]);
  1922.         HUnlock((Handle) theString);
  1923.     }
  1924. }
  1925.  
  1926. BadValue(int stringNum)
  1927. {
  1928.     StringHandle    errorStringH;
  1929.     
  1930.     if ((errorStringH = GetString(stringNum)) == NULL)
  1931.     {
  1932.         ParamText(HOPELESSLY_FATAL_ERROR, NULL, NULL, NULL);
  1933.     }
  1934.     else
  1935.     {
  1936.         MoveHHi((Handle) errorStringH);
  1937.         HLock((Handle) errorStringH);
  1938.         ParamText(*errorStringH, NULL, NULL, NULL);
  1939.         HUnlock((Handle) errorStringH);
  1940.     }
  1941.     StopAlert(ERROR_EDIT_TEXT, NULL);
  1942. }
  1943.  
  1944. IntroDialog(void)
  1945. {
  1946.     GrafPtr        savePort;
  1947.     DialogPtr    theDialog;
  1948.     Rect        dialogRect, clippingRect;
  1949.     GrafPtr        dLogOffscreen;
  1950.     int            itemHit, i, beginTicks, currentTicks, h;
  1951.  
  1952.     GetPort(&savePort);
  1953.  
  1954.     if ((theDialog = GetNewDialog(INTRO_DIALOG, NULL, M_T_F)) == NULL)
  1955.     {
  1956.         ErrorHandler(NO_WIND);
  1957.     }
  1958.     CenterWindow(theDialog);
  1959.     ShowWindow(theDialog);
  1960.     
  1961.     SetPort(theDialog);
  1962.  
  1963.     dialogRect = theDialog->portRect;
  1964.     if (!CreateOffscreenBitMap(&dLogOffscreen, &dialogRect)) 
  1965.     {
  1966.         SysBeep(1);
  1967.         ExitToShell();
  1968.     }
  1969.     
  1970.     SetPort(dLogOffscreen);
  1971.     
  1972.     DrawPicture(GetPicture(475), &dialogRect);
  1973.   
  1974.     SetPort(theDialog);
  1975.     
  1976.     DoSound(INTRO_SOUND, TRUE);
  1977.     
  1978.     h = (dialogRect.bottom - dialogRect.top) / 2;
  1979.     
  1980.     SetRect(&clippingRect, dialogRect.left, h, dialogRect.right, h);
  1981.     for (i = 1; i <= h + 1; i += 4)
  1982.     {
  1983.         ClipRect(&clippingRect);
  1984.         clippingRect.top -= 4;
  1985.         clippingRect.bottom += 4;
  1986.         CopyBits(&dLogOffscreen->portBits, &theDialog->portBits,
  1987.             &dialogRect, &dialogRect, srcCopy, NULL);            
  1988.         beginTicks = TickCount();
  1989.         do
  1990.         {
  1991.             currentTicks = TickCount();
  1992.         }
  1993.         while ((currentTicks - beginTicks) <= 2);
  1994.     }
  1995.     
  1996.     while (!Button());
  1997.     
  1998.     DisposDialog(theDialog);
  1999.     SetPort(savePort);
  2000. }
  2001.